#include "stdint.h"
#include "string.h"
#include "gd32f10x.h"
#include "DRV_WS2812B.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define WS_TRANSFER_SIZE   (WS2812_PIXELS*24)   // Transfer dataSize

#define WS_BIT              24
#define WS_BIT1             0x7C
#define WS_BIT0             0x60

/*******************************************************************************
 * Variables
 ******************************************************************************/
volatile uint8_t g_WS2812TxBuf[WS_TRANSFER_SIZE];   // WS2812 Strip transmit data buffer

typedef union WS2812_ARGB
{
    struct
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
        uint8_t a;
    }s_argb;
    uint32_t u32_rgba;
}WS2812_ARGB_U;

/*
 * @brief   WS2812_StripInit
 * @param   NULL
 * @return  NULL
 */
void WS2812_Init(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOA);
    /*SPI2_MOSI(PB15) GPIO pin configuration */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15 | GPIO_PIN_13);
    /* SPI0_SCK(PA5), SPI0_MISO(PA6) and SPI0_MOSI(PA7) GPIO pin configuration */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);

    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_SPI1);
    /* SPI0 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_BDTRANSMIT;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_8;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(WS2812_SPI, &spi_init_struct);

    /* enable SPI */
    spi_enable(WS2812_SPI);
  
    memset((void *)g_WS2812TxBuf, 0x00, WS_TRANSFER_SIZE);    
}


/*
 * @brief   WS2812_PixelSetBuff
 * @param   n, LED num / c, color / brightness, brightness
 * @return  NULL
 */
void WS2812_PixelSetIndexColor(uint16_t n, uint32_t color)
{
    volatile WS2812_ARGB_U l_color;
    
    if(n < WS2812_PIXELS)
    {
        memset((void *)&g_WS2812TxBuf[n*WS_BIT], WS_BIT0, 24);
        l_color.u32_rgba = color;

        if( ((l_color.s_argb.g>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+0] = WS_BIT1;
        if( ((l_color.s_argb.g>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+1] = WS_BIT1;
        if( ((l_color.s_argb.g>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+2] = WS_BIT1;
        if( ((l_color.s_argb.g>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+3] = WS_BIT1;
        if( ((l_color.s_argb.g>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+4] = WS_BIT1;
        if( ((l_color.s_argb.g>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+5] = WS_BIT1;
        if( ((l_color.s_argb.g>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+6] = WS_BIT1;
        if( ((l_color.s_argb.g>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+7] = WS_BIT1;
        
        if( ((l_color.s_argb.r>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+0] = WS_BIT1;
        if( ((l_color.s_argb.r>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+1] = WS_BIT1;
        if( ((l_color.s_argb.r>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+2] = WS_BIT1;
        if( ((l_color.s_argb.r>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+3] = WS_BIT1;
        if( ((l_color.s_argb.r>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+4] = WS_BIT1;
        if( ((l_color.s_argb.r>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+5] = WS_BIT1;
        if( ((l_color.s_argb.r>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+6] = WS_BIT1;
        if( ((l_color.s_argb.r>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+7] = WS_BIT1;
        
        if( ((l_color.s_argb.b>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+0] = WS_BIT1;
        if( ((l_color.s_argb.b>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+1] = WS_BIT1;
        if( ((l_color.s_argb.b>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+2] = WS_BIT1;
        if( ((l_color.s_argb.b>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+3] = WS_BIT1;
        if( ((l_color.s_argb.b>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+4] = WS_BIT1;
        if( ((l_color.s_argb.b>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+5] = WS_BIT1;
        if( ((l_color.s_argb.b>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+6] = WS_BIT1;
        if( ((l_color.s_argb.b>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+7] = WS_BIT1;
    }
}

void WS2812_PixelSetIndexRGB(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
{    
    if(n < WS2812_PIXELS)
    {
        memset((void *)&g_WS2812TxBuf[n*WS_BIT], WS_BIT0, 24);

        if( ((g>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+0] = WS_BIT1;
        if( ((g>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+1] = WS_BIT1;
        if( ((g>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+2] = WS_BIT1;
        if( ((g>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+3] = WS_BIT1;
        if( ((g>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+4] = WS_BIT1;
        if( ((g>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+5] = WS_BIT1;
        if( ((g>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+6] = WS_BIT1;
        if( ((g>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 0+7] = WS_BIT1;
        
        if( ((r>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+0] = WS_BIT1;
        if( ((r>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+1] = WS_BIT1;
        if( ((r>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+2] = WS_BIT1;
        if( ((r>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+3] = WS_BIT1;
        if( ((r>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+4] = WS_BIT1;
        if( ((r>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+5] = WS_BIT1;
        if( ((r>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+6] = WS_BIT1;
        if( ((r>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+ 8+7] = WS_BIT1;
        
        if( ((b>>7)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+0] = WS_BIT1;
        if( ((b>>6)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+1] = WS_BIT1;
        if( ((b>>5)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+2] = WS_BIT1;
        if( ((b>>4)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+3] = WS_BIT1;
        if( ((b>>3)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+4] = WS_BIT1;
        if( ((b>>2)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+5] = WS_BIT1;
        if( ((b>>1)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+6] = WS_BIT1;
        if( ((b>>0)&0x01))  g_WS2812TxBuf[n*WS_BIT+16+7] = WS_BIT1;
    }
}
/*
 * @brief   strip_clear, clean-up LED strip display
 * @param   NULL
 * @return  NULL
 */
void WS2812_ClearData(void)
{
    memset((void *)&g_WS2812TxBuf[0], WS_BIT0, (WS_TRANSFER_SIZE));//
}


/*!
    \brief      send a byte through the SPI interface and return the byte received from the SPI bus
    \param[in]  byte: byte to send
    \param[out] none
    \retval     the value of the received byte
*/
uint8_t spi_write_byte(uint8_t byte)
{
    /* loop while data register in not emplty */
    while (RESET == spi_i2s_flag_get(WS2812_SPI, SPI_FLAG_TBE));
    /* send byte through the SPI0 peripheral */
    spi_i2s_data_transmit(WS2812_SPI, byte);
    /* return the byte read from the SPI bus */
    return 0;
}

/*
 * @brief   color_dim dimme color
 * @param   color, number of LEDs
 * @return  dimmed color
 */
void WS2812_SendData(void)
{
    volatile uint32_t i;
    
    for(i=0; i<WS_TRANSFER_SIZE; i++)
    {
        spi_write_byte(g_WS2812TxBuf[i]);
    }
}

void WS2812_ShowRGB(uint8_t r,uint8_t g,uint8_t b)
{
	uint8_t 	i;

	for(i=0; i<WS2812_PIXELS; i++)
	{
		WS2812_PixelSetIndexRGB(i, r,g,b);
	}
    WS2812_SendData();
}

void WS2812_ShowColor(uint32_t color)
{
	uint8_t 	i;

	for(i=0; i<WS2812_PIXELS; i++)
	{
		WS2812_PixelSetIndexColor(i, color);
	}
    WS2812_SendData();
}

void WS2812_ShowBuff(uint8_t *buff)
{
	uint8_t i;
	uint8_t *pLedData = buff;

    for(i=0; i<WS2812_PIXELS; i++)
	{
		WS2812_PixelSetIndexRGB(i, pLedData[0],pLedData[1],pLedData[2]);
        pLedData += 3;
	}
    WS2812_SendData();
}
// end file


